package jmine.tec.hydra.domain.filter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import jmine.tec.hydra.HydraMessages;
import jmine.tec.hydra.api.HydraMessage;
import jmine.tec.hydra.domain.HydraSystem;
import jmine.tec.hydra.exception.HydraException;
import jmine.tec.hydra.script.FilterScriptContext;
import jmine.tec.persist.annotation.Alias;
import jmine.tec.persist.annotation.Constraint;
import jmine.tec.persist.annotation.Index;
import jmine.tec.persist.annotation.UniqueConstraint;
import jmine.tec.script.ScriptExecutorException;
import jmine.tec.script.persistent.domain.Script;
import bancosys.tec.component.Documentation;
import bancosys.tec.persist.bussobj.PersistableBusinessObject;
import bancosys.tec.persist.persister.annotation.NaturalKey;

/**
 * Filtro de mensagens de integração. Sua execução pode alterar a mensagem antes do envio ou após seu recebimento. Alterações feita por
 * filtros não são persistidas, elas funcionam apenas para o processamento.
 * 
 * @author piercio
 */
@Entity
@Table(name = "HYDRA_FILTER")
@Alias("HYDFTR")
@SequenceGenerator(name = "SEQ_HYDFTR", sequenceName = "SEQ_HYDFTR")
@Documentation("FILTRO DE CODIFICACAO/DECODIFICACAO.")
public class HydraFilter extends PersistableBusinessObject {

    private Long id;

    private String mnemonico;

    private String action;

    private HydraSystem system;

    private Script script;

    private HydraFilterType filterType;

    private boolean active;

    /**
     * @return o valor do campo id.
     */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_HYDFTR")
    @Column(name = "COD_HYDRA_FILTER", nullable = false)
    @Documentation("CODIGO DO FILTRO DE INTEGRACAO.")
    public Long getId() {
        return this.id;
    }

    /**
     * @param id o valor para o campo id.
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @return the mnemonico
     */
    @NaturalKey
    @UniqueConstraint(name = "AK_HYDFTR_0")
    @Column(name = "MNE", nullable = false)
    @Documentation("MNEMONICO DO FILTRO.")
    public String getMnemonico() {
        return this.mnemonico;
    }

    /**
     * @param mnemonico the mnemonico to set
     */
    public void setMnemonico(String mnemonico) {
        this.mnemonico = mnemonico;
    }

    /**
     * @return a ação que esse filtro se restringe, se existir.
     */
    @Column(name = "ACTION")
    @Documentation("ACAO PARA O FILTRO.")
    public String getAction() {
        return this.action;
    }

    /**
     * @param action o valor para a ação.
     */
    public void setAction(String action) {
        this.action = action;
    }

    /**
     * @return o sistema associado ao filtro.
     */
    @Index(suffix = "JT_1")
    @ManyToOne
    @JoinColumn(name = "COD_HYDRA_SYSTEM")
    @Documentation("CODIGO DO SISTEMA ALVO DO FILTRO.")
    public HydraSystem getSystem() {
        return this.system;
    }

    /**
     * @param system o valor para o sistema.
     */
    public void setSystem(HydraSystem system) {
        this.system = system;
    }

    /**
     * @return o script de execução do filtro.
     */
    @Index(suffix = "JT_0")
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "COD_HYDRA_SCRIPT", nullable = false)
    @Documentation("CODIGO DO SCRIPT DE FILTRO.")
    public Script getScript() {
        return this.script;
    }

    /**
     * @param script o valor para o script de filtro.
     */
    public void setScript(Script script) {
        this.script = script;
    }

    /**
     * @return o tipo de filtro, envio ou recebimento.
     */
    @Column(name = "FILTER_TYPE", nullable = false)
    @Constraint(name = "CK_HYDFTR_0", condition = "FILTER_TYPE IN (0,1)")
    @Documentation("TIPO DE FILTRO - SENDING (0) OU RECEIVING (1).")
    public HydraFilterType getFilterType() {
        return this.filterType;
    }

    /**
     * @param filterType o valor para o tipo de filtro.
     */
    public void setFilterType(HydraFilterType filterType) {
        this.filterType = filterType;
    }

    /**
     * Se o filtro está ativo e deve ser usado.
     * 
     * @return <code>true</code> se o filtro estiver ativo, <code>false</code> caso contrário.
     */
    @Column(name = "ENABLED")
    @Constraint(name = "CK_HYDFTR_1", condition = "ENABLED IN (0,1)")
    @Documentation("INDICA SE O FILTRO ESTA ATIVO (1) OU NAO (0).")
    public boolean isActive() {
        return this.active;
    }

    /**
     * @param active o valor para o active.
     */
    public void setActive(boolean active) {
        this.active = active;
    }

    /**
     * Executa o filtro para a dada mensagem.
     * 
     * @param message a mensagem que será filtrada.
     */
    public void execute(HydraMessage message) {
        try {
            this.script.createContext(FilterScriptContext.class).prepare(message).dispatchExecution();
        } catch (ScriptExecutorException e) {
            throw new HydraException(HydraMessages.SEND_FILTER_ERROR.create(this.script.getMnemonico(), message.getAction(),
                    message.getSystem()), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return this.getMnemonico();
    }
}
